package com.zh.webcommon.common.auditor.mp;

import com.zh.mycommon.util.crypto.AesEncryptService;
import com.zh.webcommon.common.support.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 用于mybatis的数据库字段加密组件
 * 如果注入到spring容器中，则相当于全局注册。
 * 建议局部使用，不注入spring容器。
 * 用法如下：<pre>{@code
 *       @TableField(typeHandler = EncryptTypeHandler.class)
 *       private String phone;
 * }</pre>
 *
 *
 */
@Slf4j
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptTypeHandler extends BaseTypeHandler<String> {
    private static final AesEncryptService aesEncryptService;

    static {
        String encrypt_key = SpringContextHolder.isUsable() ?
                SpringContextHolder.getProperty("encrypt.key") : System.getenv("encrypt_key");
        if (encrypt_key == null || encrypt_key.isBlank()) {
            throw new IllegalArgumentException("EncryptTypeHandler encrypt.key 缺失");
        }
        log.info("EncryptTypeHandler encrypt.key = {}", encrypt_key);
        aesEncryptService = new AesEncryptService(encrypt_key);
    }

    public EncryptTypeHandler() {
        log.info("[EncryptTypeHandler] constructor ...");
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, aesEncryptService.encrypt(parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        var columnValue = rs.getString(columnName);
        return StringUtils.isBlank(columnValue) ? columnValue : aesEncryptService.decrypt(columnValue);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        var columnValue = rs.getString(columnIndex);
        return StringUtils.isBlank(columnValue) ? columnValue : aesEncryptService.decrypt(columnValue);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        var columnValue = cs.getString(columnIndex);
        return StringUtils.isBlank(columnValue) ? columnValue : aesEncryptService.decrypt(columnValue);
    }

}